// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_FACTORY_H_
#define CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_FACTORY_H_

#include <stdint.h>

#include <memory>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/unguessable_token.h"
#include "cc/layers/video_frame_provider.h"
#include "content/common/content_export.h"
#include "content/renderer/gpu/stream_texture_host_android.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "ui/gfx/geometry/size.h"

namespace gpu {
namespace gles2 {
    class GLES2Interface;
} // namespace gles2
class GpuChannelHost;
} // namespace gpu

namespace ui {
class ContextProviderCommandBuffer;
}

namespace content {

class StreamTextureFactory;

// The proxy class for the gpu thread to notify the compositor thread
// when a new video frame is available.
class StreamTextureProxy : public StreamTextureHost::Listener {
public:
    ~StreamTextureProxy() override;

    // Initialize and bind to |task_runner|, which becomes the thread that the
    // provided callback will be run on. This can be called on any thread, but
    // must be called with the same |task_runner| every time.
    void BindToTaskRunner(
        const base::Closure& received_frame_cb,
        scoped_refptr<base::SingleThreadTaskRunner> task_runner);

    // StreamTextureHost::Listener implementation:
    void OnFrameAvailable() override;

    // Set the streamTexture size.
    void SetStreamTextureSize(const gfx::Size& size);

    // Send an IPC message to the browser process to request a java surface
    // object for the given route_id. After the the surface is created,
    // it will be passed back to the WebMediaPlayerAndroid object identified by
    // the player_id.
    void EstablishPeer(int player_id, int frame_id);

    // Sends an IPC to the GPU process.
    // Asks the StreamTexture to forward its SurfaceTexture to the
    // ScopedSurfaceRequestManager, using the gpu::ScopedSurfaceRequestConduit.
    void ForwardStreamTextureForSurfaceRequest(
        const base::UnguessableToken& request_token);

    struct Deleter {
        inline void operator()(StreamTextureProxy* ptr) const { ptr->Release(); }
    };

private:
    friend class StreamTextureFactory;
    explicit StreamTextureProxy(std::unique_ptr<StreamTextureHost> host);

    void BindOnThread();
    void Release();

    const std::unique_ptr<StreamTextureHost> host_;

    // Protects access to |received_frame_cb_| and |task_runner_|.
    base::Lock lock_;
    base::Closure received_frame_cb_;
    scoped_refptr<base::SingleThreadTaskRunner> task_runner_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxy);
};

typedef std::unique_ptr<StreamTextureProxy, StreamTextureProxy::Deleter>
    ScopedStreamTextureProxy;

// Factory class for managing stream textures.
class CONTENT_EXPORT StreamTextureFactory
    : public base::RefCounted<StreamTextureFactory> {
public:
    static scoped_refptr<StreamTextureFactory> Create(
        scoped_refptr<ui::ContextProviderCommandBuffer> context_provider);

    // Create the StreamTextureProxy object. This internally calls
    // CreateSteamTexture with the recieved arguments. CreateSteamTexture
    // generates a texture and stores it in  *texture_id, the texture is produced
    // into a mailbox so it can be shipped in a VideoFrame, it creates a
    // gpu::StreamTexture and returns its route_id. If this route_id is  invalid
    // nullptr is returned and *texture_id will be set to 0. If the route_id is
    // valid it returns StreamTextureProxy object. The caller needs to take care
    // of cleaning up the texture_id.
    ScopedStreamTextureProxy CreateProxy(unsigned texture_target,
        unsigned* texture_id,
        gpu::Mailbox* texture_mailbox);

    gpu::gles2::GLES2Interface* ContextGL();

private:
    friend class base::RefCounted<StreamTextureFactory>;
    StreamTextureFactory(
        scoped_refptr<ui::ContextProviderCommandBuffer> context_provider);
    ~StreamTextureFactory();
    // Creates a gpu::StreamTexture and returns its id.  Sets |*texture_id| to the
    // client-side id of the gpu::StreamTexture. The texture is produced into
    // a mailbox so it can be shipped in a VideoFrame.
    unsigned CreateStreamTexture(unsigned texture_target,
        unsigned* texture_id,
        gpu::Mailbox* texture_mailbox);

    scoped_refptr<ui::ContextProviderCommandBuffer> context_provider_;
    scoped_refptr<gpu::GpuChannelHost> channel_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureFactory);
};

} // namespace content

#endif // CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_FACTORY_H_
